package user_reference_impl

import (
	"context"
	"nexus/common"
	"nexus/dto"
	"nexus/internal/svc"
	"nexus/internal/types"
	"nexus/model"
	"nexus/utils"
	"nexus/utils/errorx"

	"github.com/zeromicro/go-zero/core/logc"
	"gorm.io/gorm"
)

type UserReferenceImpl struct {
	svc *svc.ServiceContext
}

func NewUserReferenceImpl(svc *svc.ServiceContext) UserReference {
	return &UserReferenceImpl{
		svc: svc,
	}
}

// 管理员权限校验
func (impl *UserReferenceImpl) adminAuth(ctx context.Context) (bool, error) {
	// 权限校验
	userID := utils.GetUserIDFromContext(ctx)
	isSuper, err := model.NewUserClient((*gorm.DB)(impl.svc.NexusDB)).IsAdminByID(userID)
	if err != nil {
		return false, err
	}
	if !isSuper {
		return false, nil
	}
	return true, nil
}

// 创建用户
func (impl *UserReferenceImpl) CreateUser(ctx context.Context, req *types.CreateUserReq) (*dto.User, error) {
	// 构建请求参数对应的model层对象
	user := &model.User{
		Username: req.Username,
		Password: req.Password,
		Nickname: req.Nickname,
		Email:    req.Email,
		Phone:    req.Phone,
		Status:   req.Status,
	}

	// 调用model层创建用户
	err := model.NewUserClient((*gorm.DB)(impl.svc.NexusDB)).CreateUser(user)
	if err != nil {
		return nil, errorx.HandlerSqlError(err)
	}

	// 创建租户默认绑定公网租户【1996042468109324288】
	err = model.NewUserTenantRelClient((*gorm.DB)(impl.svc.NexusDB)).Create(&model.UserTenantRel{
		UserID:   user.ID,
		TenantID: common.PublicTenantID,
	})
	if err != nil {
		return nil, errorx.HandlerSqlError(err)
	}

	// 获取公网租户信息
	tenant, err := model.NewTenantClient((*gorm.DB)(impl.svc.NexusDB)).FindTenantByCondition(&model.TenantCondition{
		ID: common.PublicTenantID,
	})
	if err != nil {
		return nil, err
	}

	// 将model层返回的User转换为DTO层的User
	data := dto.NewDTOTransfer().UserToDTO(user, tenant)

	return data, nil
}

// 用户登陆
func (impl *UserReferenceImpl) Login(ctx context.Context, req *types.LoginReq) (*dto.User, error) {
	// 验证码校验
	if req.Captcha != "10086" {
		return nil, errorx.CaptchaError
	}

	// 根据登陆方式构建查询条件
	condition := &model.UserCondition{}
	switch req.Method {
	case common.UsernamePasswordLogin:
		// 1. 参数校验
		if req.Username == "" || req.Password == "" {
			return nil, errorx.LoginError
		}
		// 2. 用户名密码登录
		condition = &model.UserCondition{
			Username: req.Username,
			Password: req.Password,
		}

	case common.PhonePasswordLogin:
		// 1. 参数校验
		if req.Phone == "" || req.Password == "" {
			return nil, errorx.LoginError
		}
		// 2. 手机号密码登录
		condition = &model.UserCondition{
			Phone:    req.Phone,
			Password: req.Password,
		}

	case common.PhoneCaptchaLogin:
		// 1. 校验手机验证码
		// TODO: 改成真实的手机短信验证码校验
		if req.SmsCaptcha != "10086" {
			return nil, errorx.SmsCaptchaError
		}
		// 2. 参数校验
		if req.Phone == "" {
			return nil, errorx.LoginError
		}
		condition = &model.UserCondition{
			Phone: req.Phone,
		}

	default:
		// 登陆方式不支持，直接返回失败
		return nil, errorx.FailedError
	}

	// 调用model层登陆
	user, err := model.NewUserClient((*gorm.DB)(impl.svc.NexusDB)).FindUserByCondition(condition)
	if err != nil {
		logc.Errorf(ctx, "登陆错误: %v", err)
		return nil, errorx.LoginError
	}
	if user == nil {
		return nil, errorx.LoginError
	}

	// 获取用户租户信息
	// 从utr表中获取租户ID
	utrs, err := model.NewUserTenantRelClient((*gorm.DB)(impl.svc.NexusDB)).FindByUserID(user.ID)
	if err != nil {
		logc.Errorf(ctx, "登陆-查找用户租户关系信息错误: %v", err)
		return nil, errorx.ServerError
	}
	// 过滤非公网租户
	tenantID := impl.filterPublicTenant(utrs)
	tenant, err := model.NewTenantClient((*gorm.DB)(impl.svc.NexusDB)).FindTenantByCondition(&model.TenantCondition{
		ID: tenantID,
	})
	if err != nil {
		logc.Errorf(ctx, "登陆-获取租户信息错误: %v", err)
		return nil, errorx.ServerError
	}

	// token刷新
	token, err := impl.refreshUserToken(ctx, user, tenantID)
	if err != nil {
		return nil, errorx.ServerError
	}

	// 组装返回结果
	dtoUser := dto.NewDTOTransfer().UserToDTO(user, tenant)
	dtoUser.Token = token

	return dtoUser, nil
}

func (impl *UserReferenceImpl) refreshUserToken(ctx context.Context, user *model.User, tenantID string) (string, error) {
	// 1. 如果redis中存在token，则删除redis中的token
	exit, err := impl.svc.Redis.Exists(ctx, user.ID)
	if err != nil {
		logc.Errorf(ctx, "登陆-Token存在检验错误: %v", err)
		return "", errorx.ServerError
	}
	if exit {
		err = impl.svc.Redis.Del(ctx, user.ID)
		if err != nil {
			logc.Errorf(ctx, "登陆-Token删除错误: %v", err)
			return "", errorx.ServerError
		}
	}

	// 2. 生成新的token
	tokenStr, err := impl.svc.JWT.GenerateToken(user.ID, user.Nickname, tenantID)
	if err != nil {
		logc.Errorf(ctx, "登陆-Token生成错误: %v", err)
		return "", errorx.ServerError
	}

	// 3. 将新的token写入redis
	err = impl.svc.Redis.SetnxEx(ctx, user.ID, tokenStr, impl.svc.Config.JWT.Expire)
	if err != nil {
		logc.Errorf(ctx, "登陆-Token写入错误: %v", err)
		return "", errorx.ServerError
	}

	return tokenStr, nil
}

// 用户列表
func (impl *UserReferenceImpl) UserList(ctx context.Context, req *types.UserListReq) ([]*dto.User, error) {
	// 构建查询条件
	condition := &model.UserCondition{
		Username: req.Username,
		Nickname: req.Nickname,
		Email:    req.Email,
		Phone:    req.Phone,
		TenantID: req.TenantID,
	}

	// 调用model层获取用户列表
	users, err := model.NewUserClient((*gorm.DB)(impl.svc.NexusDB)).BatchFindUserByCondition(condition, req.Page, req.Size)
	if err != nil {
		logc.Errorf(ctx, "用户列表查询错误: %v", err)
		return nil, err
	}

	// 组装用户id列表
	userIds := make([]string, 0, len(users))
	userMap := make(map[string]*model.User, len(users)) // 用于快速查找用户
	for _, user := range users {
		userIds = append(userIds, user.ID)
		userMap[user.ID] = user
	}

	// 批量查询用户绑定的租户信息
	utrsMapper, err := model.NewUserTenantRelClient((*gorm.DB)(impl.svc.NexusDB)).BatchFindByUsers(userIds)
	if err != nil {
		logc.Errorf(ctx, "用户绑定租户关系查询错误: %v", err)
		return nil, err
	}

	// 收集需要查询的租户ID
	tenantIDs := make([]string, 0, len(utrsMapper))
	tenantUserMap := make(map[string][]string) // 租户ID -> 用户ID列表

	for userID, utrs := range utrsMapper {
		tenantID := impl.filterPublicTenant(utrs)
		if tenantID != "" {
			tenantIDs = append(tenantIDs, tenantID)
			tenantUserMap[tenantID] = append(tenantUserMap[tenantID], userID)
		}
	}

	// 批量查询租户信息（避免N+1查询）
	tenants := make(map[string]*model.Tenant)
	if len(tenantIDs) > 0 {
		tenantList, err := model.NewTenantClient((*gorm.DB)(impl.svc.NexusDB)).BatchFindTenant(tenantIDs)
		if err != nil {
			logc.Errorf(ctx, "租户批量查询错误: %v", err)
			return nil, err
		}

		for _, tenant := range tenantList {
			tenants[tenant.ID] = tenant
		}
	}

	// 组装用户DTO
	userDTOs := make([]*dto.User, 0, len(users))
	for _, user := range users {
		var tenant *model.Tenant

		if utrs, exists := utrsMapper[user.ID]; exists {
			tenantID := impl.filterPublicTenant(utrs)
			if tenantID != "" {
				tenant = tenants[tenantID]
			}
		}

		userDTO := dto.NewDTOTransfer().UserToDTO(user, tenant)
		userDTOs = append(userDTOs, userDTO)
	}

	return userDTOs, nil
}

// 用户详情
func (impl *UserReferenceImpl) UserDetail(ctx context.Context) (*dto.User, error) {
	userId := utils.GetUserIDFromContext(ctx)

	// 构建查询条件
	condition := &model.UserCondition{
		ID: userId,
	}

	// 调用model层获取用户详情
	user, err := model.NewUserClient((*gorm.DB)(impl.svc.NexusDB)).FindUserByCondition(condition)
	if err != nil {
		logc.Errorf(ctx, "用户详情查询错误: %v", err)
		return nil, err
	}
	if user == nil {
		return nil, errorx.TokenInvalid
	}

	// 获取用户绑定的租户信息
	// 从utr中获取租户ID
	utrs, err := model.NewUserTenantRelClient((*gorm.DB)(impl.svc.NexusDB)).FindByUserID(user.ID)
	if err != nil {
		logc.Errorf(ctx, "用户绑定租户关系查询错误: %v", err)
		return nil, err
	}
	tenantID := impl.filterPublicTenant(utrs)
	tenant, err := model.NewTenantClient((*gorm.DB)(impl.svc.NexusDB)).FindTenantByCondition(&model.TenantCondition{
		ID: tenantID,
	})
	if err != nil {
		logc.Errorf(ctx, "租户查询错误: %v", err)
		return nil, err
	}

	// 将model层的User转换为DTO层的User
	userDTO := dto.NewDTOTransfer().UserToDTO(user, tenant)

	return userDTO, nil
}

// 从用户绑定租户关系列表中排出公网租户
func (impl *UserReferenceImpl) filterPublicTenant(utrs []*model.UserTenantRel) string {
	for _, utr := range utrs {
		if utr.TenantID != common.PublicTenantID {
			return utr.TenantID
		}
	}

	// 如果没有找到非公网租户，则返回公网租户ID
	return common.PublicTenantID
}

// 用户更新
func (impl *UserReferenceImpl) UserUpdate(ctx context.Context, req *types.UserUpdateReq) (*dto.User, error) {
	// 如果ID为空，则从上下文中获取用户ID
	userId := req.ID
	if req.ID == "" {
		userId = utils.GetUserIDFromContext(ctx)
	}

	// 构建更新条件
	updateUser := &model.User{
		ID: userId,
	}
	if req.Password != "" {
		updateUser.Password = req.Password
	}
	if req.Nickname != "" {
		updateUser.Nickname = req.Nickname
	}
	if req.AvatarID != "" {
		updateUser.AvatarID = req.AvatarID
	}
	if req.Email != "" {
		updateUser.Email = req.Email
	}
	if req.Phone != "" {
		updateUser.Phone = req.Phone
	}

	// 调用model层更新用户信息
	err := model.NewUserClient((*gorm.DB)(impl.svc.NexusDB)).UpdateUser(updateUser)
	if err != nil {
		logc.Errorf(ctx, "用户更新错误: %v", err)
		return nil, err
	}

	// 调用model层获取用户详情
	user, err := model.NewUserClient((*gorm.DB)(impl.svc.NexusDB)).FindUserByCondition(&model.UserCondition{ID: userId})
	if err != nil {
		logc.Errorf(ctx, "用户详情查询错误: %v", err)
		return nil, err
	}

	// 将model层的User转换为DTO层的User
	userDTO := dto.NewDTOTransfer().UserToDTO(user, nil)

	return userDTO, nil
}

// 租户用户列表
func (impl *UserReferenceImpl) TenantUserList(ctx context.Context, req *types.TenantUserListReq) ([]*dto.TenantUserList, error) {
	// 1. 权限校验
	isSuper, err := impl.adminAuth(ctx)
	if err != nil {
		logc.Errorf(ctx, "管理员权限校验失败: %v", err)
		return nil, err
	}

	// 2. 查询哪些租户
	var targetTenantIDs []string
	if isSuper {
		// 超级管理员 → 查指定租户 或 查全部租户
		if req.TenantID != "" {
			targetTenantIDs = []string{req.TenantID}
		} else {
			// 全部租户
			tenants, err := model.NewTenantClient((*gorm.DB)(impl.svc.NexusDB)).BatchFindTenantByCondition(&model.TenantCondition{}, req.Page, req.Size)
			if err != nil {
				logc.Errorf(ctx, "租户列表查询错误: %v", err)
				return nil, err
			}
			// 组装租户ID列表
			for _, tenant := range tenants {
				targetTenantIDs = append(targetTenantIDs, tenant.ID)
			}
		}

	} else {
		// 普通管理员 → 仅查自己租户
		targetTenantIDs = []string{utils.GetTenantIDFromContext(ctx)}
	}

	// 3. 一次性批量查询租户-用户绑定关系
	utrs, err := model.NewUserTenantRelClient((*gorm.DB)(impl.svc.NexusDB)).BatchFindByTenantIDs(targetTenantIDs)
	if err != nil {
		logc.Errorf(ctx, "用户绑定租户关系查询错误: %v", err)
		return nil, err
	}

	// 4. 根据租户分组: tenantID => []userID
	tenantToUserIDs := make(map[string][]string)
	for _, utr := range utrs {
		tenantToUserIDs[utr.TenantID] = append(tenantToUserIDs[utr.TenantID], utr.UserID)
	}

	// 5. 批量查询所有涉及的用户
	//    收集全部 userID 去一次性查询，避免 N 次 SQL 查询
	var allUserIDs []string
	for _, uids := range tenantToUserIDs {
		allUserIDs = append(allUserIDs, uids...)
	}

	users, err := model.NewUserClient((*gorm.DB)(impl.svc.NexusDB)).BatchFindUserByCondition(&model.UserCondition{
		IDs: allUserIDs,
	}, req.Page, req.Size)
	if err != nil {
		logc.Errorf(ctx, "用户列表查询错误: %v", err)
		return nil, err
	}
	usersDTO := dto.NewDTOTransfer().BatchUserToDTO(users, nil)

	// 6. 用户 DTO 按 ID 做 map，提高组装效率
	userMap := make(map[string]*dto.User)
	for _, u := range usersDTO {
		userMap[u.ID] = u
	}

	// 7. 查询涉及的租户信息
	tenants, err := model.NewTenantClient((*gorm.DB)(impl.svc.NexusDB)).BatchFindTenantByCondition(&model.TenantCondition{
		IDs: targetTenantIDs,
	}, req.Page, req.Size)
	if err != nil {
		logc.Errorf(ctx, "租户列表查询错误: %v", err)
		return nil, err
	}

	tenantDTOs := dto.NewDTOTransfer().BatchTenantToDTO(tenants)

	tenantMap := make(map[string]*dto.Tenant)
	for _, t := range tenantDTOs {
		tenantMap[t.ID] = t
	}

	// 8. 组装最终返回结果
	var result []*dto.TenantUserList
	for tenantID, userIDs := range tenantToUserIDs {
		var list []*dto.User
		for _, uid := range userIDs {
			if userMap[uid] != nil {
				list = append(list, userMap[uid])
			}
		}

		result = append(result, &dto.TenantUserList{
			Tenant: tenantMap[tenantID],
			Users:  list,
		})
	}

	return result, nil
}
